/**
 * 
 * Copyright (C) 2011 Cody Stoutenburg . All rights reserved.
 *
 *       This program is free software; you can redistribute it and/or
 *       modify it under the terms of the GNU Lesser General Public License
 *       as published by the Free Software Foundation; either version 2.1
 *       of the License, or (at your option) any later version.
 *
 *       This program is distributed in the hope that it will be useful,
 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *       GNU Lesser General Public License for more details.
 *
 *       You should have received a copy of the GNU Lesser General Public License
 *       along with this program; if not, write to the Free Software
 *       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 * 
 */
package ca.usherbrooke.mainApp.view.goal;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import ca.usherbrooke.behaviours.goal.request.RequestAddGoal.AddGoalInfo;
import ca.usherbrooke.goal.BasicGoal;
import ca.usherbrooke.goal.IGoal;
import ca.usherbrooke.mainApp.MainAppAgent;
import ca.usherbrooke.mainApp.goal.GoalAgentBuilderViewer;
import ca.usherbrooke.model.entity.IEntityModel;
import ca.usherbrooke.utils.ExceptionTool;
import ca.usherbrooke.utils.ExternalClassLoad;

/**
 * @author Cody Stoutenburg
 * 
 */
public class PanelGoals extends JPanel {
	private static final long serialVersionUID = 1L;

	private final GoalAgentBuilderViewer agent;

	private final JComboBox entityCombobox;

	private final JSpinner scoreTotalSpinner;
	private final JSpinner scoreFailSpinner;
	private final JSpinner durationSpinner;
	private final JCheckBox checkInfiniTime;

	private final JComboBox classComboBox;
	private final JLabel description;
	private final JTextField params;

	private final JButton send;

	public PanelGoals(GoalAgentBuilderViewer agent) {
		super();
		this.agent = agent;

		this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

		entityCombobox = new JComboBox();

		scoreTotalSpinner = new JSpinner(new SpinnerNumberModel());
		scoreFailSpinner = new JSpinner(new SpinnerNumberModel());
		durationSpinner = new JSpinner(new SpinnerNumberModel(2000, 0, 100000,
				100));

		classComboBox = new JComboBox();
		classComboBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				refreshDescription();
			}
		});
		description = new JLabel();

		params = new JTextField(30);

		send = new JButton("Send");
		send.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				addGoal();
			}
		});

		JPanel panelEntity = new JPanel(new FlowLayout());
		panelEntity.add(new JLabel("Entity: "));
		panelEntity.add(entityCombobox);

		JPanel panelScoreTotal = new JPanel(new FlowLayout());
		panelScoreTotal.add(new JLabel("Score total: "));
		panelScoreTotal.add(scoreTotalSpinner);

		JPanel panelScoreFail = new JPanel(new FlowLayout());
		panelScoreFail.add(new JLabel("Score fail: "));
		panelScoreFail.add(scoreFailSpinner);

		JPanel panelDuration = new JPanel(new FlowLayout());
		panelDuration.add(new JLabel("Duration: "));
		panelDuration.add(durationSpinner);
		checkInfiniTime = new JCheckBox("No duration");
		checkInfiniTime.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				checkDurationHappen();
			}
		});
		panelDuration.add(checkInfiniTime);

		JPanel panelClass = new JPanel(new FlowLayout());
		panelClass.add(new JLabel("Class :"));
		panelClass.add(classComboBox);

		JPanel panelParams = new JPanel(new FlowLayout());
		panelParams.add(new JLabel("Parameters: "));
		panelParams.add(params);

		this.add(panelEntity);
		this.add(panelScoreTotal);
		this.add(panelScoreFail);
		this.add(panelDuration);
		this.add(panelClass);
		this.add(description);
		this.add(panelParams);
		this.add(send);

		refreshClasses();
		refreshDescription();
		refreshEntities();
	}

	private void refreshEntities() {
		List<IEntityModel> allEntities = this.agent.getWorld().getAllEntities();
		for (IEntityModel entity : allEntities) {
			entityCombobox.addItem(entity.getGuid());
		}
	}

	private void checkDurationHappen() {
		durationSpinner.setEnabled(!this.checkInfiniTime.isSelected());
	}

	private void refreshClasses() {
		List<String> allClasses = getClasses(MainAppAgent.DIRECTORY_GOAL);

		for (String classname : allClasses) {
			if (ExternalClassLoad.verifyClass(MainAppAgent.DIRECTORY_GOAL,
					IGoal.class, classname, false)) {
				classComboBox.addItem(classname);
			}
		}
	}

	private void refreshDescription() {
		String classname = (String) classComboBox.getSelectedItem();

		if (classname != null) {
			String desc = "aucune description";
			try {
				Class<?> c = ExternalClassLoad.getClass(
						MainAppAgent.DIRECTORY_GOAL, classname);
				Method m = c.getDeclaredMethod("getGeneralDescription",
						(Class<?>[]) null);
				desc = (String) m.invoke((Object[]) null, (Object[]) null);
			} catch (Exception ex) {
				ExceptionTool
						.showError("Fail to load the goal description", ex);
			}
			description.setText(desc);
		}
	}

	private List<String> getClasses(File root) {
		List<String> allPackages = new ArrayList<String>();
		File[] allFiles = root.listFiles();
		for (File f : allFiles) {
			if (f.isDirectory()) {
				allPackages.addAll(getFilesName(f, ""));
			} else {
				allPackages.add(ExternalClassLoad.toClassName(f.getName()));
			}
		}

		return allPackages;
	}

	private List<String> getFilesName(File root, String path) {
		List<String> allFiles = new ArrayList<String>();

		File[] files = root.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				allFiles.addAll(getFilesName(file, path + root.getName() + "."));
			} else {
				allFiles.add(path + root.getName() + "."
						+ ExternalClassLoad.toClassName(file.getName()));
			}
		}
		return allFiles;
	}

	private void addGoal() {
		String classname = (String) classComboBox.getSelectedItem();
		String params = this.params.getText();

		try {
			Long guid = (Long) entityCombobox.getSelectedItem();
			Float scoreTotal = ((Integer) scoreTotalSpinner.getValue())
					.floatValue();
			Float scoreFail = ((Integer) scoreFailSpinner.getValue())
					.floatValue();

			Long duration = ((Integer) durationSpinner.getValue()).longValue();
			if (checkInfiniTime.isSelected()) {
				duration = BasicGoal.INFINITY_TIME;
			}

			this.agent.addGoal(new AddGoalInfo(guid, scoreTotal, scoreFail,
					duration, MainAppAgent.DIRECTORY_GOAL.getCanonicalPath(),
					classname, params));
		} catch (IOException ex) {
			ExceptionTool.showError("Fail to add goal", ex);
		}
	}
}
